



#include "WinInput.h"

#include <stdio.h>



struct DIData { //handy data for callbacks
	LPDIRECTINPUT8*  ppDI; 
	LPDIRECTINPUTDEVICE8* ppDevice;     
};

BOOL CALLBACK EnumKeyboardCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
{
	HRESULT hr;
	LPDIRECTINPUT8 pDI = *(((DIData*)pContext)->ppDI);
	LPDIRECTINPUTDEVICE8* ppKeyboard = ((DIData*)pContext)->ppDevice;

	// Obtain an interface to the enumerated joystick.
	hr = pDI->CreateDevice(pdidInstance->guidInstance, ppKeyboard, NULL);
	if(FAILED(hr)) 
		return DIENUM_CONTINUE;

	return DIENUM_STOP;
} 

BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
{
	HRESULT hr;
	LPDIRECTINPUT8 pDI = *(((DIData*)pContext)->ppDI);
	LPDIRECTINPUTDEVICE8* ppJoystick = ((DIData*)pContext)->ppDevice;

	// Obtain an interface to the enumerated joystick.
	hr = pDI->CreateDevice(pdidInstance->guidInstance, ppJoystick, NULL);
	if(FAILED(hr)) 
		return DIENUM_CONTINUE;

	return DIENUM_STOP;
} 

BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext )
{
	LPDIRECTINPUTDEVICE8 Joystick = *(((DIData*)pContext)->ppDevice);

	DIPROPRANGE diprg; 
	diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
	diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
	diprg.diph.dwHow        = DIPH_BYID; 
	diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
	diprg.lMin              = -1000; 
	diprg.lMax              = +1000; 

	// Set the range for the axis
	if( FAILED( Joystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) )
		return DIENUM_STOP;

	return DIENUM_CONTINUE;
}


WinInput::WinInput() {
	m_pDI=NULL;
	m_pJoystick=NULL;
	for (int i=0; i<256;i++) {
		KeyState[i]=0;	
	}
}


WinInput::~WinInput() {
	Destroy();
}


void WinInput::Destroy() {
	if( m_pJoystick ) m_pJoystick->Unacquire();

	if (m_pJoystick!=NULL) {m_pJoystick->Release();m_pJoystick=NULL;}
	if (m_pDI!=NULL) {m_pDI->Release();m_pDI=NULL;}
}


HRESULT WinInput::Create(HINSTANCE Instance, HWND hWnd) {
	HRESULT hr;

	Destroy();//cleanup if previous device exists 


	if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
										 IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
		return hr;

	DIData DIInfo;
	DIInfo.ppDI=&m_pDI;
	DIInfo.ppDevice=&m_pJoystick;

	if( FAILED( hr = m_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, 
										 EnumJoysticksCallback,
										 (VOID*)&DIInfo, DIEDFL_ATTACHEDONLY ) ) )
		return hr;

	// Make sure we got a joystick
	if( NULL != m_pJoystick ){


		if( FAILED( hr = m_pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) )
			return hr;

		if( FAILED( hr = m_pJoystick->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND ) ) )
			return hr;

		// Determine how many axis the joystick has (so we don't error out setting
		// properties for unavailable axis)
		m_diDevCaps.dwSize = sizeof(DIDEVCAPS);
		if ( FAILED( hr = m_pJoystick->GetCapabilities(&m_diDevCaps) ) )
			return hr;

		DIInfo.ppDI=&m_pDI;
		DIInfo.ppDevice=&m_pJoystick;
		// Enumerate the axes of the joyctick and set the range of each axis.
		if ( FAILED( hr = m_pJoystick->EnumObjects( EnumAxesCallback, (VOID*)&DIInfo, DIDFT_AXIS ) ) )
			return hr;

		DIPROPRANGE dipr;
		dipr.diph.dwHeaderSize=sizeof(DIPROPHEADER) ;
		dipr.diph.dwSize=sizeof(DIPROPRANGE) ;
		dipr.diph.dwObj=0;
		dipr.diph.dwHow=DIPH_DEVICE;
		dipr.lMax=0;
		dipr.lMin=0;

		m_pJoystick->GetProperty(DIPROP_RANGE  , (DIPROPHEADER*)&dipr);
		JoyMax=dipr.lMax;
		JoyMin=dipr.lMin;

	}else{
		MessageBox( NULL, L"Joystick not found. ",L"Error",MB_ICONERROR | MB_OK );
	}

	DIInfo.ppDevice=&m_pKeyboard;
	if( FAILED( hr = m_pDI->EnumDevices( DI8DEVCLASS_KEYBOARD, 
										 EnumKeyboardCallback,
										 (VOID*)&DIInfo, DIEDFL_ATTACHEDONLY ) ) )
		return hr;

	if( NULL != m_pKeyboard ){

		if( FAILED( hr = m_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
			return hr;

		if( FAILED( hr = m_pKeyboard->SetCooperativeLevel( hWnd, DISCL_NONEXCLUSIVE ) ) )
			return hr;

	}else{
		MessageBox( NULL, L"Keyboard not found. ",L"Error",MB_ICONERROR | MB_OK );
	}
	return S_OK;
}


HRESULT WinInput::Update()
{
	HRESULT     hr;

	if( NULL != m_pJoystick ) {
		// Poll the device to read the current state
		hr = m_pJoystick->Poll(); 
		if( FAILED(hr) ) {
			hr = m_pJoystick->Acquire();
			while( hr == DIERR_INPUTLOST ) 
				hr = m_pJoystick->Acquire();

			return S_OK; 
		}

		// Get the input's device state
		if( FAILED( hr = m_pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &JoyState ) ) )
			return hr; // The device should have been acquired during the Poll()
	}
	if( NULL != m_pKeyboard ) {
		// Poll the device to read the current state
		hr = m_pKeyboard->Poll(); 
		if( FAILED(hr) ) {
			hr = m_pKeyboard->Acquire();
			while( hr == DIERR_INPUTLOST ) 
				hr = m_pKeyboard->Acquire();

			return S_OK; 
		}

		// Get the input's device state
		if( FAILED( hr = m_pKeyboard->GetDeviceState( 256, KeyState ) ) )
			return hr; // The device should have been acquired during the Poll()
	}

	return S_OK;
}